package entity

import (
	"database/sql"
	"github.com/astaxie/beego/orm"
	"github.com/gomodule/redigo/redis"
	"nspel/nspel"
	"strconv"
	"time"
)

type Area struct {
	Id                  int64           `orm:"pk;auto;column(id)" json:"id,omitempty"`
	CountryId           int64           `orm:"column(country_id)" json:"countryId,omitempty"`
	ProvinceId          int64           `orm:"column(province_id)" json:"provinceId,omitempty"`
	CityId              int64           `orm:"column(city_id)" json:"cityId,omitempty"`
	UserId              sql.NullInt64   `orm:"column(user_id)" json:"userId,omitempty"`
	Name                string          `orm:"column(name)" json:"name,omitempty"`
	IsExperiment        bool            `orm:"column(is_experiment)" json:"isExperiment,omitempty"`
	AllSchoolNum        int64           `orm:"column(all_school_num)" json:"allSchoolNum,omitempty"`
	AuthorizedSchoolNum int64           `orm:"column(authorized_school_num)" json:"authorizedSchoolNum,omitempty"`
	StandoutSchoolNum   int64           `orm:"column(standout_school_num)" json:"standoutSchoolNum,omitempty"`
	Contact             sql.NullString  `orm:"column(contact)" json:"contact,omitempty"`
	ContactPhone        sql.NullString  `orm:"column(contact_phone)" json:"contactPhone,omitempty"`
	ContactEmail        sql.NullString  `orm:"column(contact_email)" json:"contactEmail,omitempty"`
	ContactAddress      sql.NullString  `orm:"column(contact_address)" json:"contactAddress,omitempty"`
	ExperimentAt        time.Time       `orm:"column(experiment_at)" json:"experimentAt"`
	StandoutAt          time.Time       `orm:"column(standout_at)" json:"standoutAt"`
	JoinYear            sql.NullInt64   `orm:"column(join_year)" json:"joinYear,omitempty"`
	Score               sql.NullFloat64 `orm:"column(score)"`
	CreateAt            time.Time       `orm:"auto_now_add;type(datetime);column(created_at)" json:"createAt"`
	UpdateAt            time.Time       `orm:"auto_now;type(datetime);column(updated_at)" json:"updateAt"`
}

func init() {
	orm.RegisterModel(new(Area))
}

func (*Area) TableName() string {
	return "area"
}

func (a *Area) SelectAllByName(name string) (*[]Area, error) {
	key := "area"
	hashKey := "name[\"" + name + "\"]"
	var area []Area
	err := nspel.RedisHgetJson(key, hashKey, &area)
	if err == nil {
		return &area, nil
	}
	if err != redis.ErrNil {
		nspel.Error(err)
	}
	_, err = nspel.GetOrmEngine().QueryTable(a.TableName()).Filter("name", name).All(&area)
	if err != nil || len(area) == 0 {
		return &area, err
	}
	nspel.RedisHsetJson(key, hashKey, &area)
	return &area, nil
}

func (a *Area) SelectAllByCityIdName(cityId int64, name string) error {
	a.CityId = cityId
	a.Name = name
	key := "area"
	hashKey := "cityId[" + strconv.FormatInt(cityId, 10) + "].name[\"" + name + "\"]"
	err := nspel.RedisHgetJson(key, hashKey, a)
	if err == nil {
		return nil
	}
	if err != redis.ErrNil {
		nspel.Error(err)
	}
	err = nspel.GetOrmEngine().Read(a, "city_id", "name")
	if err != nil {
		return err
	}
	nspel.RedisHsetJson(key, hashKey, a)
	return nil
}

func (a *Area) SelectAllDistinctJoinYear() (*orm.ParamsList, error) {
	key := "area"
	hashKey := "joinYear.distinct"
	var list orm.ParamsList
	err := nspel.RedisHgetJson(key, hashKey, list)
	if err == nil {
		return &list, nil
	}
	if err != redis.ErrNil {
		nspel.Error(err)
	}
	_, err = nspel.GetOrmEngine().QueryTable(a.TableName()).Distinct().ValuesFlat(&list, "join_year")
	if err != nil {
		return nil, err
	}
	nspel.RedisHsetJson(key, hashKey, list)
	return &list, nil
}

func (a *Area) SelectAllDistinctJoinYearByCountryIdProvinceIdCityIdAreaName(countryId int64, provinceId int64, cityId int64, areaName string) (*orm.ParamsList, error) {
	key := "area"
	hashKey := ""
	db := nspel.GetOrmEngine().QueryTable(a.TableName())
	if countryId > 0 {
		hashKey += "countryId[" + strconv.FormatInt(countryId, 10) + "]."
		db = db.Filter("country_id", countryId)
	}
	if provinceId > 0 {
		hashKey += "provinceId[" + strconv.FormatInt(provinceId, 10) + "]."
		db = db.Filter("province_id", provinceId)
	}
	if cityId > 0 {
		hashKey += "cityId" + strconv.FormatInt(cityId, 10) + "]."
		db = db.Filter("city_id", provinceId)
	}
	if len(areaName) == 0 {
		hashKey += "name[%\"" + areaName + "\"%]"
		db = db.Filter("name__contains", areaName)
	}
	hashKey += "joinYear.distinct"
	var list orm.ParamsList
	err := nspel.RedisHgetJson(key, hashKey, list)
	if err == nil {
		return &list, nil
	}
	if err != redis.ErrNil {
		nspel.Error(err)
	}
	_, err = nspel.GetOrmEngine().QueryTable(a.TableName()).Distinct().ValuesFlat(&list, "join_year")
	if err != nil {
		return nil, err
	}
	nspel.RedisHsetJson(key, hashKey, list)
	return &list, nil
}

func (a *Area) SelectAllByUserId(userId int64) (err error) {
	key := "area"
	hashKey := "userId[" + strconv.FormatInt(userId, 10) + "]"
	err = nspel.RedisHgetJson(key, hashKey, a)
	if err == nil {
		return
	}
	if err != redis.ErrNil {
		nspel.Error(err)
	}
	a.UserId = sql.NullInt64{Int64: int64(userId), Valid: true}
	err = nspel.GetOrmEngine().Read(a, "user_id")
	if err != nil {
		return
	}
	nspel.RedisHsetJson(key, hashKey, a)
	return
}

func (a *Area) SelectAllById(id int64) (err error) {
	key := "area"
	hashKey := "id[" + strconv.FormatInt(id, 10) + "]"
	err = nspel.RedisHgetJson(key, hashKey, a)
	if err == nil {
		return
	}
	if err != redis.ErrNil {
		nspel.Error(err)
	}
	a.Id = id
	err = nspel.GetOrmEngine().Read(a)
	if err != nil {
		return
	}
	nspel.RedisHsetJson(key, hashKey, a)
	return
}

func (a *Area) SelectAll() (areas *[]Area, err error) {
	key := "area"
	hashKey := "all"
	areas = new([]Area)
	err = nspel.RedisHgetJson(key, hashKey, areas)
	if err == nil {
		return
	}
	if err != redis.ErrNil {
		nspel.Error(err)
	}
	_, err = nspel.GetOrmEngine().QueryTable(a.TableName()).All(areas)
	if err != nil || len(*areas) == 0 {
		return
	}
	nspel.RedisHsetJson(key, hashKey, areas)
	return
}

func (a *Area) SelectAllByProvinceIdCityIdNameJoinYear(ormEng *orm.QuerySeter, hashKey string) (areas *[]Area, err error) {
	key := "area"
	areas = new([]Area)
	err = nspel.RedisHgetJson(key, hashKey, areas)
	if err == nil {
		return
	}
	if err != redis.ErrNil {
		nspel.Error(err)
	}
	_, err = (*ormEng).All(areas)
	if err != nil || len(*areas) == 0 {
		return
	}
	nspel.RedisHsetJson(key, hashKey, areas)
	return
}

func (a *Area) SelectCountByProvinceIdCityIdNameJoinYear(ormEng *orm.QuerySeter, hashKey string) (count int64, err error) {
	key := "area"
	count, err = nspel.RedisHgetInt64(key, hashKey)
	if err == nil {
		return
	}
	if err != redis.ErrNil {
		nspel.Error(err)
	}
	count, err = (*ormEng).Count()
	if err != nil {
		return
	}
	nspel.RedisHsetInt64(key, hashKey, count)
	return
}

func (a *Area) SelectAllByCityId(cityId int64) ([]Area, error) {
	key := "area"
	hashKey := "cityId[" + strconv.FormatInt(cityId, 10) + "]"
	var areas []Area
	err := nspel.RedisHgetJson(key, hashKey, &areas)
	if err == nil {
		return areas, nil
	}
	if err != redis.ErrNil {
		nspel.Error(err)
	}
	_, err = nspel.GetOrmEngine().QueryTable(a.TableName()).Filter("city_id", cityId).All(&areas)
	if err != nil || len(areas) == 0 {
		return areas, err
	}
	nspel.RedisHsetJson(key, hashKey, areas)
	return areas, err
}

func (a *Area) DeleteById(id int64) (err error) {
	a.Id = id
	_, err = nspel.GetOrmEngine().Delete(a)
	return
}

func (a *Area) Insert() error {
	_, err := nspel.GetOrmEngine().Insert(a)
	return err
}

func (a *Area) Update(columns ...string) error {
	_, err := nspel.GetOrmEngine().Update(a, columns...)
	return err
}

func (a *Area) ImportInsert() error {
	if a.ContactPhone.Valid && len(a.ContactPhone.String) != 0 {
		manager := new(Manager)
		err := manager.SelectAllByUserName(a.ContactPhone.String)
		if err != nil {
			if err == orm.ErrNoRows {
				a.UserId, err = manager.Register(manager.UserName, manager.UserName, ManagerAuthority.Area)
				if err != nil {
					return err
				}
			} else {
				return err
			}
		} else {
			a.UserId = sql.NullInt64{Int64: int64(manager.Id), Valid: true}
		}
	}
	err := a.Insert()
	return err
}

func (a *Area) ImportUpdate() error {
	if a.ContactPhone.Valid && len(a.ContactPhone.String) != 0 && !a.UserId.Valid {
		manager := new(Manager)
		err := manager.SelectAllByUserName(a.ContactPhone.String)
		if err != nil {
			if err == orm.ErrNoRows {
				a.UserId, err = manager.Register(manager.UserName, manager.UserName, ManagerAuthority.Area)
				if err != nil {
					return err
				}
			} else {
				return err
			}
		} else {
			a.UserId = sql.NullInt64{Int64: int64(manager.Id), Valid: true}
		}
	}
	err := a.Update("user_id", "is_experiment", "all_school_num", "contact", "contact_phone", "contact_email", "contact_address", "experiment_at", "standout_at", "join_year")
	return err
}

func (a *Area) UpdateAuthorizedSchoolNumStandoutSchoolNum() error {
	var areas []Area
	_, err := nspel.GetOrmEngine().QueryTable(a.TableName()).All(&areas)
	if err != nil {
		return err
	}
	for i := 0; i < len(areas); i++ {
		school := new(School)
		school.ExperimentAreaId = areas[i].Id
		count, err := nspel.GetOrmEngine().QueryTable(school.TableName()).Filter("experiment_area_id", areas[i].Id).Count()
		if err != nil {
			return err
		}
		areas[i].AuthorizedSchoolNum = int64(count)
		count, err = nspel.GetOrmEngine().QueryTable(school.TableName()).Filter("experiment_area_id", areas[i].Id).Filter("is_standout", true).Count()
		if err != nil {
			return err
		}
		areas[i].StandoutSchoolNum = int64(count)
		_, err = nspel.GetOrmEngine().Update(&areas[i], "authorized_school_num", "standout_school_num")
		if err != nil {
			return err
		}
	}
	return nil
}

func (a *Area) IsBelongCity(city *City, areaSlice []Area) *Area {
	for i := 0; i < len(areaSlice); i++ {
		if areaSlice[i].CountryId == city.CountryId && areaSlice[i].ProvinceId == city.ProvinceId && areaSlice[i].CityId == city.Id {
			return &areaSlice[i]
		}
	}
	return nil
}

func (a *Area) Copy(area *Area) {
	a.Id = area.Id
	a.CountryId = area.CountryId
	a.ProvinceId = area.ProvinceId
	a.CityId = area.CityId
	a.UserId = area.UserId
	a.Name = area.Name
	a.IsExperiment = area.IsExperiment
	a.AllSchoolNum = area.AllSchoolNum
	a.AuthorizedSchoolNum = area.AuthorizedSchoolNum
	a.StandoutSchoolNum = area.StandoutSchoolNum
	a.Contact = area.Contact
	a.ContactPhone = area.ContactPhone
	a.ContactEmail = area.ContactEmail
	a.ContactAddress = area.ContactAddress
	a.ExperimentAt = area.ExperimentAt
	a.StandoutAt = area.StandoutAt
	a.JoinYear = area.JoinYear
	a.CreateAt = area.CreateAt
	a.UpdateAt = area.UpdateAt
}

func (a *Area) SelectCountByProvinceIdIsExperiment(provinceId int64, isExperiment bool) (int64, error) {
	key := "area"
	hashKey := "provinceId[" + strconv.FormatInt(provinceId, 10) + "].isExperiment[" + strconv.FormatBool(isExperiment) + "].count"
	count, err := nspel.RedisHgetInt64(key, hashKey)
	if err == nil {
		return count, err
	}
	if err != redis.ErrNil {
		nspel.Error(err)
	}
	count, err = nspel.GetOrmEngine().QueryTable(a.TableName()).Filter("province_id", provinceId).Filter("is_experiment", isExperiment).Count()
	nspel.RedisHsetInt64(key, hashKey, count)
	return count, err
}
